/**
 * grid
 *
 */

define([
  'jquery'
], function($) {
  'use strict';

  function Grid(table) {
    var $table = $(table)
    if (!$table.hasClass('table')) {
      throw new Error('not .table')
    }
    this.$table = $(table)
  }

  Grid.prototype = {
    init: function() {
      var $table = this.$table
      this.$tbody = $table.children('tbody')
      this.$toggleAll = $table.find('.toggle-all')
      this.$moveup = $table.find('.moveup')
      this.enableSwap = this.$moveup.length > 0
      this._grid(false)
      this._bindEvents()
      if (this.enableSwap) {
        this._swapHelper()
      }
    },
    /**
     * 搜索行
     * @param  {boolean} all 设置所有复选框的状态
     */
    _grid: function(all) {
      var grid = []
      var $trs = this.$tbody.children('tr')
      if (typeof all === 'boolean') {
        $trs.each(function() {
          var $this = $(this)
          var item = {
            id: $this.data('id'),
            checked: all
          }
          $this.find('.toggle').prop('checked', all)
          grid.push(item)
        })
      } else {
        $trs.each(function() {
          var $this = $(this)
          var item = {
            id: $this.data('id'),
            checked: $this.find('.toggle').prop('checked')
          }
          grid.push(item)
        })
      }
      this.$trs = $trs
      this.grid = grid
    },
    _bindEvents: function() {
      var $table = this.$table
      this.$toggleAll.on('change', $.proxy(this._toggleAll, this))
      $table.on('change', '.toggle', $.proxy(this._toggle, this))
      $table.on('click', '.disabled', function(e) {
        e.preventDefault()
      })
    },
    /**
     * 主动点击全选框时，所有复选框要改变状态。
     * 复选框的状态变化时（包括点击，添加行，删除行），全选框需要跟着变
     */
    _toggleAll: function(e) {
      var checked = $(e.target).prop('checked')
      this._grid(checked)
    },
    _toggle: function(e) {
      var el = e.target
      var i = this.getIndex(el)
      this.grid[i].checked = el.checked
      this._notifyToggleAll()
    },
    _notifyToggleAll: function() {
      var len = this.grid.length
      this.$toggleAll.prop('checked', this.getSelected().count === len)
    },
    update: function() {
      this._grid()
      this._notifyToggleAll()
      if (this.enableSwap) {
        this._swapHelper()
      }
    },
    /**
     * 获取元素所在行的 id
     * @param  {dom} el
     * @return {number}
     */
    getId: function(el) {
      return $(el).closest('tr').data('id')
    },
    /**
     * 获取元素所在行的 index
     * @param  {dom} el
     * @return {number}
     */
    getIndex: function(el) {
      return this.getCurrent(el).index
    },
    /**
     * 获取当前行的信息
     * @param  {dom} el
     * @return {object} 结构如下
     * {
     *   id: id, // 当前行的 id
     *   index: index // 当前行的 index
     *  }
     */
    getCurrent: function(el) {
      var id = this.getId(el)
      var grid = this.grid
      var i = grid.length

      while (i--) {
        if (grid[i].id === id) {
          return {
            id: id,
            index: i
          }
        }
      }
    },
    /**
     * 获取选中行的信息
     * @return {object} 结构如下
     * {
     *   ids: [], // 选中行的 id
     *   indexes: [], // 选中行的 index
     *   count: 0 // 选中行的个数
     * }
     */
    getSelected: function() {
      var grid = this.grid
      var i = grid.length
      var obj = {
        id: [],
        index: [],
        count: 0
      }

      while (i--) {
        if (grid[i].checked) {
          obj.id.push(grid[i].id)
          obj.index.push(i)
        }
      }

      obj.count = obj.id.length
      return obj
    },
    /**
     * 添加行
     * row 为此行 html:
     * <tr data-id=""><td><input type="checkbox" class="toggle" /></td></tr>
     */
    add: function(rows) {
      this.$tbody.append(rows)
      this.update()
    },
    /**
     * 删除行
     * @param  {array} indexes 行的索引
     */
    del: function(indexes) {
      var $trs = this.$trs
      $.each(indexes, function(index, i) {
        $trs.eq(i).remove()
      })
      this.update()
    },
    /**
     * 交换相邻行
     * @param  {number} from 当前行的索引
     * @param  {number} to 目标行的索引
     * 朝下 to = from + 1 朝上 to = from -1
     * 第一行不能朝上移动，最后一行不能朝下移动, 给它们添加类 disabled
     */
    swap: function(from, to) {
      if (to === -1 || to === this.grid.length || from === to) {
        return
      }

      var $trs = this.$trs
      var $from = $trs.eq(from)
      var $to = $trs.eq(to)
      // TODO: 检查是否保持 checkbox 状态
      if (to > from) {
        $from.replaceWith($to.after($from.clone(true)))
      } else {
        $from.replaceWith($to.before($from.clone(true)))
      }
      this.update()
    },
    _swapHelper: function() {
      var $moveup = this.$table.find('.moveup')
      var $movedown = this.$table.find('.movedown')
      var klass = 'disabled'
      $moveup.each(function() {
        var $this = $(this)
        if ($(this).hasClass(klass)) {
          $this.removeClass(klass)
          return false
        }
      })
      $moveup.eq(0).addClass(klass)
      $movedown.each(function() {
        var $this = $(this)
        if ($(this).hasClass(klass)) {
          $this.removeClass(klass)
          return false
        }
      })
      $movedown.eq(-1).addClass(klass)
    }
  }

  return Grid

})
